package com.sumkor.processor;

import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Names;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.tools.Diagnostic;
import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author Sumkor
 * @since 2021/12/27
 */
public abstract class BaseProcessor extends AbstractProcessor {

    protected Messager messager;   // 用来在编译期打log用的
    protected JavacTrees trees;    // 提供了待处理的抽象语法树
    protected TreeMaker treeMaker; // 封装了创建AST节点的一些方法
    protected Names names;         // 提供了创建标识符的方法

    /**
     *  设置jbUnwrap方法调用的次数,因为如果不设置,当printMessage打印的信息相同时,只打印第一次调用的信息.
      */

    private volatile static AtomicInteger i = new AtomicInteger(0);

    /**
     * 获取编译阶段的一些环境信息
     */
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        Messager messager1 = processingEnv.getMessager();

        messager1.printMessage(Diagnostic.Kind.NOTE, "---BaseProcessor类的init方法执行了---"
                        + "processingEnv转化前的hashCode是:" + System.identityHashCode(processingEnv) + "---线程是:" + Thread.currentThread()
                        + "---线程的hashCode:" + (System.identityHashCode(Thread.currentThread())
                        + "----processingEnv.getClass: " + processingEnv.getClass()
                        + "---processingEnv instanceof ProcessingEnvironment结果:" + (processingEnv instanceof ProcessingEnvironment)
                        + "---i=" + i
                )
        );

        // jbUnwrap方法中,将processingEnv转化了,和SetterProcessor类中init方法中的processingEnv的hashCode不一致.
        processingEnv = jbUnwrap(ProcessingEnvironment.class, processingEnv);

        processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "---BaseProcessor类的init方法执行了---"
                        + "processingEnv转化后的hashCode是:" + System.identityHashCode(processingEnv) + "---线程是:" + Thread.currentThread()
                        + "---线程的hashCode:" + (System.identityHashCode(Thread.currentThread())
                        + "----processingEnv.getClass: " + processingEnv.getClass()
                        + "---processingEnv instanceof ProcessingEnvironment结果:" + (processingEnv instanceof ProcessingEnvironment)
                        + "---i=" + i
                )
        );

        super.init(processingEnv);

        this.messager = processingEnv.getMessager();// messager 在这里才初始化. 所以前面不能有 this.messager.xx方法调用
        this.trees = JavacTrees.instance(processingEnv);
        Context context = ((JavacProcessingEnvironment) processingEnv).getContext();
        this.treeMaker = TreeMaker.instance(context);
        this.names = Names.instance(context);

    }

    /**
     * 获取 IDEA 环境下的 ProcessingEnvironment
     */
    private synchronized static <T> T jbUnwrap(Class<? extends T> iface, T wrapper) {

        T unwrapped = null;

        ProcessingEnvironment pe = (ProcessingEnvironment) wrapper;
        Messager messager1 = pe.getMessager();

        messager1.printMessage(Diagnostic.Kind.NOTE, "---BaseProcessor类的jbUnwrap方法执行了----马上开始进入try语句了-----i=" + i);

        try {

            final Class<?> apiWrappers = wrapper.getClass().getClassLoader().loadClass("org.jetbrains.jps.javac.APIWrappers");
            final Method unwrapMethod = apiWrappers.getDeclaredMethod("unwrap", Class.class, Object.class);
            unwrapped = iface.cast(unwrapMethod.invoke(null, iface, wrapper));

        } catch (Throwable ignored) {
            messager1.printMessage(Diagnostic.Kind.NOTE, "---BaseProcessor类的jbUnwrap方法执行了----进入catch语句了-----i=" + i);
        }

        if (unwrapped != null) {
            messager1.printMessage(Diagnostic.Kind.NOTE, "---BaseProcessor类的jbUnwrap方法执行了----判断unwrapped不为空,即将返回unwrapped:" + unwrapped + "---i=" + i);
        } else {
            messager1.printMessage(Diagnostic.Kind.NOTE, "---BaseProcessor类的jbUnwrap方法执行了----判断unwrapped为空,即将返回wrapper:" + wrapper + "---i=" + i);
        }

        i.getAndIncrement();

        return unwrapped != null ? unwrapped : wrapper;
    }

}